
// Body represents a body or object in space with 3D-position, velocity and mass.
// This class will be used by the executable class 'Space'. A body moves through space according to
// its inertia and - if specified - an additional force exerted on it (for example the
// gravitational force of another mass).
public class Body {

    // private members
    private double mass;
    private double x, y, z;
    private double dx, dy, dz;

    // constructor
    public Body() {}

    public double getMass() { return mass; }

    /**
     * set method for mass of body
     * @param mass represents the mass to be assigned
     */
    public void setMass(double mass) { this.mass = mass; }

    /**
     * set method for initial position of body
     * @param x x component of position
     * @param y y component of position
     * @param z z component of position
     */
    public void setPosition(double x, double y, double z) {
        this.x = x; this.y = y; this.z = z;
    }

    /**
     * set method for velocity of body, fixes a trajectory for
     * translation of body
     * @param dx x component of force
     * @param dy y component of force
     * @param dz z component of force
     */
    public void setVelocity(double dx, double dy, double dz) {
        this.dx = dx; this.dy = dy; this.dz = dz;
    }

    /**
     * abstracts the canonical height component of our body, which is
     * the vertical displacement along our z axis
     * @return z component of position
     */
    public double height() { return z; }

    /**
     * abstracts a position that is to be attributed to our body at a specific
     * point in time
     * @return a double[] containing a parameter for every spacial dimension
     * of body
     */
    public double[] position() { return new double[] { x, y, z }; }

    /**
     * 0d (and to encompass potential lower values, negative values too) is
     * by convention defined to be a "ground", by which we evaluate whether a
     * body is at the "ground", this is particularly useful for simulations
     * of bodies on places like earth where our ground convention makes sense
     * @return truthy when body is at or below ground
     */
    public boolean atGround() {
        return z <= 0d;
    }

    /**
     * translates this body by forces dx, dy, dz
     */
    public void move() {
        x = x + dx; y = y + dx; z = z + dz;
    }

    /**
     * applies a force with 3 vector components on this particular body,
     * thereby affecting the next translation
     * @param fx x component of force
     * @param fy y component of force
     * @param fz z component of force
     */
    public void move(double fx, double fy, double fz) {
        // when a force f is applied, the new trajectory is governed
        // by the equation d = d + f / m
        dx = dx + fx / mass;
        dy = dy + fy / mass;
        dz = dz + fz / mass;
        move();
    }

    /**
     * applies a force similarly to the second-less variant of this method,
     * but for a duration given by parameter seconds
     * @param seconds duration of force
     * @param fx x component of force
     * @param fy y component of force
     * @param fz z component of force
     */
    public void move(int seconds, double fx, double fy, double fz) {
        if (seconds <= 0) return;
        move(fx, fy, fz);
        move(--seconds, fx, fy, fz);
    }

    @Override
    public String toString() {
        return String.format("body %f @ (%g, %g, %g) + delta (%g, %g, %g)", mass, x, y, z, dx, dy, dz);
    }
}
